#include <fstream>

#include "topconn_error.hpp"
#include "topconn_logutil.hpp"

#include "httpclient.hpp"

#include "httplib.h"

namespace topconn
{
	HttpClient::HttpClient()
		: m_httpClientPtr(nullptr)
		, m_maxConnTimeout(5)
		, m_maxRecvTimeout(30)
		, m_isIpv6(false)
		, m_isKeepalive(false)
	{
	}

	HttpClient::HttpClient(const string& url)
		: m_httpClientPtr(nullptr)
		, m_url(url)
		, m_maxConnTimeout(5)
		, m_maxRecvTimeout(30)
		, m_isIpv6(false)
		, m_isKeepalive(false)
	{
	}

	HttpClient::~HttpClient()
	{
	}

	void HttpClient::setUrl(const string& url)
	{
		m_url = url;
	}

	void HttpClient::setMaxTimeout(uint16_t maxTimeout)
	{
		m_maxRecvTimeout = maxTimeout;
	}

	void HttpClient::setMaxConnTimeout(uint16_t maxConnTimeout)
	{
		m_maxConnTimeout = maxConnTimeout;
	}

	void HttpClient::setIpv6(bool on)
	{
		m_isIpv6 = on;
	}

	void HttpClient::setKeepalive(bool on)
	{
		m_isKeepalive = on;
	}

	void HttpClient::setUserAndPass(const string& username, const string& password)
	{
		m_username = username;
		m_password = password;
	}

	const string& HttpClient::getUrl() const
	{
		return m_url;
	}

	uint16_t HttpClient::getMaxTimeout() const
	{
		return m_maxRecvTimeout;
	}

	uint16_t HttpClient::getMaxConnTimeout() const
	{
		return m_maxConnTimeout;
	}

	bool HttpClient::isIpv6() const
	{
		return m_isIpv6;
	}

	bool HttpClient::isKeepalive() const
	{
		return m_isKeepalive;
	}

	int  HttpClient::initClient()
	{
		if (!m_httpClientPtr)
		{
			m_httpClientPtr = std::make_shared<httplib::Client>(m_url);
			m_httpClientPtr->set_connection_timeout(m_maxConnTimeout,0);
			m_httpClientPtr->set_read_timeout(m_maxRecvTimeout,0);

			if (m_isIpv6)
				m_httpClientPtr->set_address_family(AF_INET6);

			if (m_isKeepalive)
				m_httpClientPtr->set_keep_alive(true);

			if (!m_username.empty())
				m_httpClientPtr->set_basic_auth(m_username,m_password);
		}
		return 0;
	}

	int HttpClient::request(const string& method, const string& path, const string& body,const string& content_type, string& response)
	{
		int iRet = 0;
		httplib::Error error;

		if (!m_httpClientPtr)
		{
			TLOG_ERROR("invalid httpclient handle");
			return INVALID_HANDLE;
		}

		if (method == "post")
		{
			httplib::Result result = m_httpClientPtr->Post(path, body, content_type);
			error = result.error();
			if (error == httplib::Error::Success)
			{
				response = result->body;
				return SUCESSED;
			}
		}
		else if (method == "get")
		{
			httplib::Result result = m_httpClientPtr->Get(path);
			error = result.error();
			if (result.error() == httplib::Error::Success)
			{
				if (!body.empty())
				{
					std::ofstream out;
					out.open(body, std::ios_base::binary | std::ios::out);
					if (!out.is_open())
					{
						TLOG_ERROR("open file [%s] error:%s",strerror(errno));
						return OTHER_ERROR;
					}
					out << result->body;
				}
				else
				{
					response = result->body;
				}
				return SUCESSED;
			}
		}
		else if (method == "put")
		{
			httplib::Result result = m_httpClientPtr->Put(path, body, content_type);
			error = result.error();
			if (result.error() == httplib::Error::Success)
			{
				response = result->body;
				return SUCESSED;
			}
		}
		else if (method == "delete")
		{
			httplib::Result result = m_httpClientPtr->Delete(path);
			error = result.error();
			if (result.error() == httplib::Error::Success)
			{
				response = result->body;
				return SUCESSED;
			}
		}
		TLOG_ERROR("method=[%s] path=[%s] error=[%d]", method.c_str(), path.c_str(),error);
		if (error == httplib::Error::Connection)
			return CONNECT_ERROR;
		else if (error == httplib::Error::ConnectionTimeout)
			return CONNECT_TIMEOUT;
		else if(error == httplib::Error::Write)
			return SEND_ERROR;
		else if (error == httplib::Error::Read)
			return RECV_ERROR;
		return OTHER_ERROR;
	}
};